/*
 * @Author: zzy 917106840648 NJUST
 * @Date: 2020-03-24 08:55:51
 * @LastEditTime: 2020-04-03 22:08:32
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \W+compiler\SyntacticAnalyzer.h
 */

#ifndef SYNTACTICANALYZER_H_
#define SYNTACTICANALYZER_H_

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <ctype.h>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <map>
#include <set>
#include <sstream>
#include <stack>
#include <vector>

using namespace std;

//定义 action中 acc 移进 规约 error 错误的状态码
enum actionState {
    acc = 0,
    shift,
    reduce,
    err,
};

/**
 * @description: string 切割
 * @param {type}
 * @return:
 */
string stringCut(const string input, int i, int j);

/**
 * @description: char 2 string
 * @param {type}
 * @return:
 */
string char2string(char a);
//定义 LR(1) 产生式类 包括左部非终结符、右部、附加终结符
class Production {
    friend class Item;
    friend class Lr;
    friend class LrS;

  public:
    //构造函数
    Production(const string& input);
    Production(const char&      proBegin,
               const string&    proEnd,
               const set<char>& additionalSymbol)
        : proBegin(proBegin), proEnd(proEnd), additionalSymbol(additionalSymbol)
    {
    }

    /**
     * @description: show 产生式
     * @param {type}
     * @return:
     */
    void show();

    /**
     * @description: 将产生式转化为 string
     * @param {type}
     * @return:
     */
    string production_to_string();

    /**
     * @description: 判断两个 production 是否相等
     * @param {type}
     * @return:
     */
    friend bool operator==(const Production& a, const Production& b)
    {
        bool flag = true;
        if (a.proBegin == b.proBegin && a.proEnd == b.proEnd) {
            set<char>::iterator ita = a.additionalSymbol.begin();
            set<char>::iterator itb = b.additionalSymbol.begin();
            for (; ita != a.additionalSymbol.end(); ita++, itb++) {
                if ((*itb) != (*itb)) {
                    flag = false;
                    break;
                }
            }
            if (flag) {
                return true;
            }
            return false;
        }
        return false;
    }

  private:
    char      proBegin;          //左部
    string    proEnd;            //右部
    set<char> additionalSymbol;  //附加终结符
    bool      isEclosure;        //判断是否进行了eclosure操作
};

//项目集 类
class Item {
    friend class Lr;
    friend class LrS;

  public:
    /**
     * @description: 添加新的项目集
     * @param {type}
     * @return:
     */
    void addItem(const string& input);

    /**
     * @description:展示项目集
     * @param {type}
     * @return:
     */
    void show();

    /**
     * @description:展示 终结符 非终符
     * @param {type}
     * @return:
     */
    void showFinal();

    /**
     * @description: 判断两个项目集是否相等
     * @param {type}
     * @return:
     */
    friend bool operator==(const Item& a, const Item& b)
    {
        if (a.production.size() != b.production.size()) {
            return false;
        }
        else {
            return a.production == b.production;
        }
        return false;
    }

  private:
    vector<Production> production;  //产生式 集合
    set<char>          unFinal;     //非终结符
    set<char>          final;       //终结符
    set<char>          allSymbol;   //终结符 非终结符并集
};

/**
 * 需要的函数：
 * 1.求 FIRST 集
 * 2.求项目集闭包 eclosure
 * 3.构建转换 go函数 用来计算 状态到状态的转换 I,X -> I
 * 4.项目状态集 DFA函数
 * 5.构建ACTION表 GOTO表
 * 6.分析函数
 */

// LR 类
class Lr {
  public:
    /**
     * @description: 添加Item
     * @param {type}
     * @return:
     */
    void addItem(string s);

    /**
     * @description: 从文件中读取 到 输入栈 并读取TOKEN.txt到行数栈
     * @param {type}
     * @return:
     */
    void getInputStack(string input);

    /**
     * @description: 展示 输入栈
     * @param {type}
     * @return:
     */
    void showInputStack();

    /**
     * @description: 展示状态栈
     * @param {type}
     * @return:
     */
    void showStateStack();

    /**
     * @description: 展示分析栈
     * @param {type}
     * @return:
     */
    void showAnalyzeStack();

    /**
     * @description: 1.求得 FIRST 集
     * @param {type}
     * @return:
     */
    set<char> getFirst(string& str);

    /**
     * @description: 2.计算项目集 I 的 e-closure集
     * @param {type}
     * @return:
     */
    Item eclosure(Item I);

    /**
     * @description: 3.计算项目集 I 经过 char X后的项目集
     * @param {type}
     * @return: eclosure(J)
     */
    Item Go(Item I, char X);

    /**
     * @description: 4.根据 初始 Item 求项目集 的 DFA
     * @param {type}
     * @return:
     */
    void itemDFA();

    /**
     * @description:5.构建 ACTION GOTO 表
     * @param {type}
     * @return:
     */
    void getAG();

    /**
     * @description: 6.语法分析的分析过程
     * @param {type}
     * @return:
     */
    void parser();

    /**
     * @description: 7.错误分析
     * @param {type}
     * @return:
     */
    void getError();

    /**
     * @description: 添加产生式
     * @param {type}
     * @return:
     */
    void addProduction(string& str);

    /**
     * @description: 展示分析过程
     * @param {type}
     * @return:
     */
    void show();

    /**
     * @description: LR运行
     * @param {type}
     * @return:
     */
    void run();

    /**
     * @description: 展示 FIRST ACTION GOTO
     * @param {type}
     * @return:
     */
    void showAFG();

  protected:
    Item         G;        //文法G 初始的文法 列表
    vector<Item> program;  //项目集规范组

    //各种栈
    vector<char> inputStack;    //输入栈
    vector<int>  stateStack;    //状态栈
    vector<char> analyzeStack;  //分析栈
    vector<int>  lineStack;     //行数栈

    // FIRST集 用于中间生成
    map<char, set<char>> FIRST;

    // ACTION表 int + char -> char + int
    map<pair<int, char>, pair<actionState, int>> ACTION;
    // GOTO表 int + char -> int
    map<pair<int, char>, int> GOTO;
};

/**
 * @description: 打开文件
 * @param {type}
 * @return:
 */
void LfileOpen();

/**
 * @description: 关闭文件
 * @param {type}
 * @return:
 */
void LfileClose();

/**
 * @description: 判断是否为界符
 * @param {type}
 * @return:
 */
bool isDelimiterS(char a);

#endif  // !SYNTACTICANALYZER_H_
